package com.justgame.project.generator.schema;

import com.google.common.base.CaseFormat;
import lombok.Getter;
import lombok.Setter;
import org.springframework.lang.NonNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static com.justgame.project.generator.schema.Join.leftJoin;

/**
 * 实体类
 */
@Getter
public class Entity {
    // 模块名
    private final String moduleName;
    // 业务实体名
    private final String name;
    // 表明
    private final String tableName;
    // 描述
    private final String comment;
    // 字段
    private final List<Field> fields;
    // 表关联构建器
    private final List<Join.JoinBuilder> joinTableBuilders;
    // 建立索引字段
    private final List<String> indexFieldNames;
    // 自定义服务
    private final List<Service.ServiceEach> serviceItems;
    // 字段枚举值
    private final List<Enumerate> enums;
    // 实体类型
    private final Type entityType;
    // 表关联
    @Setter
    private List<Join> joinTables;
    // 父类
    @Setter
    private Class<?> superClass;

    public Entity(Entity.Builder builder){
        this.name = builder.name;
        this.comment = builder.comment;
        this.entityType = builder.entityType;
        this.moduleName = builder.module;
        this.tableName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,this.name);
        this.fields = builder.fields;
        this.joinTableBuilders = builder.joinTableBuilders;
        this.indexFieldNames = builder.indexFieldNames;
        this.enums = builder.enums;
        this.serviceItems = builder.serviceItems;
    }

    public Optional<Field> findFieldByName(String name){
        return fields.stream().filter(field -> field.getName().equals(name)).findFirst();
    }

    public Optional<Enumerate> findEnumByFieldName(String fieldName){
        return enums.stream().filter(enu->enu.getFieldName().equals(fieldName)).findFirst();
    }

    public boolean hasEncryptField(){
        return fields.stream().anyMatch(Field::isEncrypt);
    }

    public static Builder baseEntityBuilder(@NonNull String module, @NonNull String name, @NonNull String comment){
        return new Builder(module,name,comment,Type.BASE_ENTITY)
                .fields(
                        Field.key("id","主键"),
                        Field.dateTime("createDate","创建日期"),
                        Field.key("createUser","创建用户"),
                        Field.dateTime("updateDate","更新日期"),
                        Field.key("updateUser","更新用户"),
                        Field.bool("isDel","逻辑删除"),
                        Field.integer("versions","版本号")
                )
                .joinTables(
                        leftJoin("createUser","createUser","SysUserInfo","id"),
                        leftJoin("updateUser","updateUser","SysUserInfo","id")
                );
    }

    public static Builder builder(@NonNull String module, @NonNull String name, @NonNull String comment){
        return new Builder(module,name,comment,Type.BASE_TABLE)
                .fields(
                        Field.key("id","主键"),
                        Field.integer("versions","版本号")
                );
    }

    public static class Builder{
        private final String module;
        private final String name;
        private final String comment;
        private final List<Field> fields = new ArrayList<>();
        private final List<String> indexFieldNames = new ArrayList<>();
        private final List<Join.JoinBuilder> joinTableBuilders = new ArrayList<>();
        private final List<Enumerate> enums = new ArrayList<>();
        private final List<Service.ServiceEach> serviceItems = new ArrayList<>();
        private final Type entityType;

        public Builder(@NonNull String module,@NonNull String name,@NonNull String comment,@NonNull Type entityType){
            this.module = module;
            this.name = name;
            this.comment = comment;
            this.entityType = entityType;
        }

        public Builder fields(Field... fields){
            this.fields.addAll(Arrays.asList(fields));
            return this;
        }

        public Builder joinTables(Join.JoinBuilder... joinTableBuilders){
            this.joinTableBuilders.addAll(Arrays.asList(joinTableBuilders));
            return this;
        }

        public Builder enums(Enumerate... enums){
            this.enums.addAll(Arrays.asList(enums));
            return this;
        }

        public Builder service(List<Service.ServiceEach> serviceItems){
            this.serviceItems.addAll(serviceItems);
            return this;
        }

        public Entity build(){
            return new Entity(this);
        }
    }

    public enum Type{
        BASE_ENTITY,
        BASE_TABLE
    }
}
